const _ = require("lodash");

const {
  readAllValues,
} = require("../awakened-potential/helpers/readAllValues.js");

const allValues = readAllValues("m");

// ========== 分组策略实现 ==========
class GroupStrategyAnalyzer {
  constructor(groups) {
    this.groups = groups;
    this.groupStrategies = {};
    this.initializeStrategies();
  }

  initializeStrategies() {
    for (const group of this.groups) {
      this.groupStrategies[group.group_name] = {
        group,
        killNextAccuracy: [],
      };
    }
  }

  updateStrategies(history, currentIndex) {
    if (currentIndex === 0) return;

    for (const [groupName, strategy] of Object.entries(this.groupStrategies)) {
      const prevNumber = history[currentIndex - 1].number;
      const currentNumber = history[currentIndex].number;

      // 查找前一个号码所在的子分组
      let prevSubgroup = null;
      for (const subgroup of strategy.group.group_data) {
        if (subgroup.includes(parseInt(prevNumber))) {
          prevSubgroup = subgroup;
          break;
        }
      }

      // 检查当前号码是否在前一个号码的组中
      const killedCorrectly = prevSubgroup
        ? !prevSubgroup.includes(parseInt(currentNumber))
        : false;

      strategy.killNextAccuracy.push(killedCorrectly ? 1 : 0);
    }
  }

  getTopStrategies(topN = 3) {
    const strategyPerformance = [];

    for (const [groupName, strategy] of Object.entries(this.groupStrategies)) {
      if (strategy.killNextAccuracy.length === 0) continue;

      const accuracy =
        strategy.killNextAccuracy.reduce((sum, val) => sum + val, 0) /
        strategy.killNextAccuracy.length;

      strategyPerformance.push({
        groupName,
        accuracy,
        streak: this.calculateCurrentStreak(strategy.killNextAccuracy),
        groupType: strategy.group.group_type,
      });
    }

    return _.orderBy(
      strategyPerformance,
      ["accuracy", "streak"],
      ["desc", "desc"]
    ).slice(0, topN);
  }

  calculateCurrentStreak(accuracyArray) {
    if (accuracyArray.length === 0) return 0;

    let streak = 0;
    for (let i = accuracyArray.length - 1; i >= 0; i--) {
      if (accuracyArray[i] === 1) streak++;
      else break;
    }
    return streak;
  }

  applyGroupStrategy(prediction, topStrategy) {
    const strategy = this.groupStrategies[topStrategy.groupName];

    // 获取最近一期号码
    const lastNumber = parseInt(allValues[allValues.length - 1].number);

    // 查找最近一期号码所在的子分组
    let lastSubgroup = null;
    for (const subgroup of strategy.group.group_data) {
      if (subgroup.includes(lastNumber)) {
        lastSubgroup = subgroup;
        break;
      }
    }

    // 如果找到子分组，则排除该子分组中的号码
    if (lastSubgroup) {
      return prediction.filter((num) => !lastSubgroup.includes(num));
    }

    return prediction;
  }
}

// ========== 预测核心功能 ==========
function buildMarkovMatrix(history) {
  const matrix = Array.from({ length: 50 }, () => Array(50).fill(0));

  for (let i = 1; i < history.length; i++) {
    const prev = Number(history[i - 1].number);
    const curr = Number(history[i].number);
    if (prev >= 1 && curr >= 1 && prev <= 49 && curr <= 49) {
      matrix[prev][curr]++;
    }
  }

  for (let i = 1; i <= 49; i++) {
    const row = matrix[i];
    const sum = row.reduce((a, b) => a + b, 0);
    if (sum > 0) {
      for (let j = 1; j <= 49; j++) {
        row[j] = row[j] / sum;
      }
    }
  }

  return matrix;
}

function predictHotCold(history, hotCount = 16, coldCount = 16) {
  const countMap = Array(50).fill(0);

  for (const item of history) {
    const number = Number(item.number);
    if (number >= 1 && number <= 49) {
      countMap[number]++;
    }
  }

  const result = countMap.map((count, number) => ({ number, count })).slice(1);
  const hot = _.orderBy(result, ["count", "number"], ["desc", "asc"]).map(
    (item) => item.number
  );
  const cold = _.orderBy(result, ["count", "number"], ["asc", "asc"]).map(
    (item) => item.number
  );
  return { hot, cold };
}

function getMarkovPredictionWithFallback(
  prev,
  matrix,
  windowData,
  totalLimit = 32
) {
  const row = matrix[prev];
  if (!row) return [];

  const sorted = row
    .map((prob, number) => ({ number, prob }))
    .slice(1)
    .filter((item) => item.prob > 0)
    .sort((a, b) => b.prob - a.prob)
    .map((item) => item.number);

  let baseSet = _.uniq(sorted);
  if (baseSet.length > totalLimit) {
    return baseSet.slice(0, totalLimit).sort((a, b) => a - b);
  }

  const { hot, cold } = predictHotCold(windowData);
  const half = Math.ceil((totalLimit - baseSet.length) / 2);
  const fillHot = hot.filter((n) => !baseSet.includes(n)).slice(0, half);
  const fillCold = cold
    .filter((n) => !baseSet.includes(n) && !fillHot.includes(n))
    .slice(0, totalLimit - baseSet.length - fillHot.length);

  baseSet = _.uniq([...baseSet, ...fillHot, ...fillCold]);
  return baseSet.slice(0, totalLimit).sort((a, b) => a - b);
}

function analyzeStreaks(arr) {
  if (arr.length === 0) {
    return {
      maxStreak1: 0,
      maxStreak0: 0,
      avgStreak1: "0.00",
      avgStreak0: "0.00",
      streaks1: [],
      streaks0: [],
    };
  }

  let streaks1 = [],
    streaks0 = [];
  let current = arr[0],
    count = 1;

  for (let i = 1; i < arr.length; i++) {
    if (arr[i] === current) count++;
    else {
      (current === 1 ? streaks1 : streaks0).push(count);
      current = arr[i];
      count = 1;
    }
  }
  (current === 1 ? streaks1 : streaks0).push(count);

  const maxStreak1 = streaks1.length ? Math.max(...streaks1) : 0;
  const maxStreak0 = streaks0.length ? Math.max(...streaks0) : 0;

  return {
    maxStreak1,
    maxStreak0,
    avgStreak1: (
      streaks1.reduce((a, b) => a + b, 0) / streaks1.length || 0
    ).toFixed(2),
    avgStreak0: (
      streaks0.reduce((a, b) => a + b, 0) / streaks0.length || 0
    ).toFixed(2),
    streaks1,
    streaks0,
  };
}

// ========== 主程序入口 ==========
function main() {
  // 使用问题中提供的分组数据
  const groups = [
    // 这里插入您提供的完整分组数据
    // 由于长度限制，仅显示部分分组
    {
      group_name: "TWO_ASCENDING_GROUPS",
      group_type: "two",
      group_data: [
        [1, 2],
        [3, 4] /*...完整数据...*/,
      ],
    },
    // ...其他分组...
  ];

  const groupAnalyzer = new GroupStrategyAnalyzer(groups);
  const historyData = allValues.map((item) => ({
    time: item.time,
    number: Number(item.number),
  }));

  const windowSize = 100;
  const predictionCount = 32;

  let correct = 0;
  let wrong = 0;
  let hitArray = [];
  let groupStats = {};

  console.log(
    `\n🧠 一阶马尔科夫链 + 热冷补足 + 分组策略（窗口大小：${windowSize}），共 ${Math.max(
      0,
      historyData.length - windowSize
    )} 次预测：\n`
  );

  // 初始化分组策略
  for (let i = 0; i < historyData.length; i++) {
    groupAnalyzer.updateStrategies(historyData, i);
  }

  for (let i = windowSize; i < historyData.length; i++) {
    const actual = historyData[i];
    const prevNumber = historyData[i - 1].number;
    const windowData = historyData.slice(i - windowSize, i);

    // 获取最佳分组策略
    const topStrategies = groupAnalyzer.getTopStrategies(3);
    const bestStrategy = topStrategies.length > 0 ? topStrategies[0] : null;

    // 更新分组策略统计
    for (const strategy of topStrategies) {
      if (!groupStats[strategy.groupName]) {
        groupStats[strategy.groupName] = { hits: 0, total: 0 };
      }
      groupStats[strategy.groupName].total++;
    }

    // 生成基础预测
    const matrix = buildMarkovMatrix(historyData.slice(0, i));
    let prediction = getMarkovPredictionWithFallback(
      prevNumber,
      matrix,
      windowData,
      predictionCount
    );

    // 应用最佳分组策略
    if (bestStrategy) {
      const originalLength = prediction.length;
      prediction = groupAnalyzer.applyGroupStrategy(prediction, bestStrategy);

      // 记录分组策略效果
      const hit = prediction.includes(actual.number);
      if (hit) groupStats[bestStrategy.groupName].hits++;
    }

    // 更新分组策略历史
    groupAnalyzer.updateStrategies(historyData, i);

    // 评估预测结果
    const hit = prediction.includes(actual.number);
    hitArray.push(hit ? 1 : 0);
    hit ? correct++ : wrong++;

    // 打印当期结果
    console.log(`📅 第${i + 1}期（${actual.time}）`);
    console.log(`🎯 推荐(${prediction.length}个号码):`, prediction.join(", "));
    console.log(
      `✅ 实际号码: ${actual.number} → ${hit ? "✅ 命中" : "❌ 未命中"}`
    );

    if (bestStrategy) {
      console.log(
        `🏆 使用分组策略: ${bestStrategy.groupName} (类型:${
          bestStrategy.groupType
        }, 准确率:${(bestStrategy.accuracy * 100).toFixed(1)}%)`
      );
    }

    console.log("---------------------------------------------------\n");
  }

  // 汇总统计
  if (historyData.length <= windowSize) {
    console.log("⚠️ 数据不足，需要至少100期历史数据进行预测");
    return;
  }

  const { maxStreak1, maxStreak0, avgStreak1, avgStreak0 } =
    analyzeStreaks(hitArray);
  const accuracy = ((correct / (correct + wrong)) * 100).toFixed(2);

  console.log("\n🎯 预测结果统计");
  console.log(`总预测期数: ${correct + wrong}`);
  console.log(`✅ 命中期数: ${correct}`);
  console.log(`❌ 错误期数: ${wrong}`);
  console.log(`📊 命中率: ${accuracy}%`);

  console.log("\n📈 连续预测表现分析：");
  console.log(`✅ 最大连续命中次数: ${maxStreak1}`);
  console.log(`❌ 最大连续失败次数: ${maxStreak0}`);
  console.log(`✅ 平均连续命中长度: ${avgStreak1}`);
  console.log(`❌ 平均连续失败长度: ${avgStreak0}`);

  // 分组策略表现统计
  console.log("\n🏆 分组策略表现统计:");
  for (const [groupName, stats] of Object.entries(groupStats)) {
    const hitRate =
      stats.total > 0 ? ((stats.hits / stats.total) * 100).toFixed(2) : 0;
    console.log(`▸ ${groupName}: 使用次数 ${stats.total}, 命中率 ${hitRate}%`);
  }
}

// 启动程序
main();
